#pragma once

#include <iostream>
#include <vector>
#include <unordered_map>
#include <thread>
#include <mutex>
#include <algorithm>

#include <time.h>
#include <assert.h>

#include "log.hpp"

#ifdef _WIN32
    #include <windows.h>
#elif  __linux__
    //#include <sys/mman.h>
    #include <unistd.h>
#endif


using std::cout;
using std::endl;
using namespace ns_log;


static const size_t MAX_BYTES = 256 * 1024;
static const size_t NFREE_LIST = 208;
static const size_t NPAGES = 129;
static const size_t PAGE_SHIFT = 13;

#ifdef _WIN64
// _WIN64 代码
typedef long long PAGE_ID;
#elif _WIN32
// _WIN32 代码
typedef int PAGE_ID;
#elif __LP64__
// __LP64__ 代码
typedef long long PAGE_ID;
#elif __ILP32__
// __ILP32__ 代码
typedef size_t PAGE_ID;
#endif



inline static size_t MIN(size_t a, size_t b)
{
#ifdef  _WIN64
    return min(a, b);
#elif  __linux
    return std::min(a, b);
#endif
}

// 直接去堆上按页申请空间
inline static void* SystemAlloc(size_t kpage)
{
#ifdef _WIN32
    void* ptr = VirtualAlloc(0, kpage << 13, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (ptr == nullptr)
        throw std::bad_alloc();
    return ptr;
#elif  __linux__ 
    // 用mmap有点问题！！！！！！！
    // void* ptr = mmap(nullptr, kpage << PAGE_SHIFT, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    void* ptr = sbrk(kpage << PAGE_SHIFT);
    if (ptr == (void*)(-1))
        throw std::bad_alloc();
    return ptr;
#endif
}
inline static void SystemFree(void *ptr, size_t bytes)
{
    #ifdef _WIN32
	VirtualFree(ptr, 0, MEM_RELEASE);
#else
	sbrk(-bytes);
#endif
}




static void*& Nextobj(void* obj)
{
    return *(void**)obj;
}
class FreeList
{
public:
    void Push(void* obj)
    {
        // 头插
        Nextobj(obj) = _free_list;
        _free_list = obj;
        _size++;
    }

    void PushRang(void* start, void* end, size_t n)
    {
        Nextobj(end) = _free_list;
        _free_list = start;
        _size += n;
    }

    void* Pop()
    {
        // 头删
        assert(_free_list);
        void* obj = _free_list;
        _free_list = Nextobj(obj);
        _size--;
        return obj;
    }

    void PopRang(void*& start, void*& end, size_t n)
    {
        assert(n <= _size);
        start = _free_list;
        end = start;

        for (int i = 0; i < n - 1; i++)
        {
            end = Nextobj(end);
        }
        _free_list = Nextobj(end);
        Nextobj(end) = nullptr;
        _size -= n;
    }

    bool Empty()
    {
        return _free_list == nullptr;
    }

    size_t& Maxsize()
    {
        return _maxsize;
    }

    size_t Size()
    {
        return _size;
    }

private:
    void* _free_list = nullptr;
    size_t _maxsize = 1;
    size_t _size = 0;
};

// 对象大小的对齐映射规则
class SizeClass
{
public:
    // 整体控制在最多10%左右的内碎片浪费
    // [1,128]					8byte对齐	     freelist[0,16)
    // [128+1,1024]				16byte对齐	     freelist[16,72)
    // [1024+1,8*1024]			128byte对齐	     freelist[72,128)
    // [8*1024+1,64*1024]		1024byte对齐     freelist[128,184)
    // [64*1024+1,256*1024]		8*1024byte对齐   freelist[184,208)

    // static inline size_t _RoundUp(size_t size, size_t alignNum)
    // {
    //     size_t alignSize;
    //     if (size % alignNum != 0)
    //     {
    //         alignSize = (size / alignNum + 1) * alignNum;
    //     }
    //     else
    //     {
    //         alignSize = size;
    //     }
    //     return alignSize;
    // }

    static inline size_t _RoundUp(size_t bytes, size_t alignNum)
    {
        return ((bytes + alignNum - 1) & ~(alignNum - 1));
    }

    static inline size_t RoundUp(size_t size)
    {
        if (size <= 128)
        {
            return _RoundUp(size, 8);
        }
        else if (size <= 1024)
        {
            return _RoundUp(size, 16);
        }
        else if (size <= 8 * 1024)
        {
            return _RoundUp(size, 128);
        }
        else if (size <= 64 * 1024)
        {
            return _RoundUp(size, 1024);
        }
        else if (size <= 256 * 1024)
        {
            return _RoundUp(size, 8 * 1024);
        }
        else
        {
            return _RoundUp(size, 1<<PAGE_SHIFT);
        }
    }

    static inline size_t _Index(size_t bytes, size_t align_shift)
    {
        return ((bytes + (1 << align_shift) - 1) >> align_shift) - 1;
    }
    static inline size_t Index(size_t bytes)
    {
        assert(bytes <= MAX_BYTES);

        static int group_array[4] = { 16, 56, 56, 56 };
        if (bytes < 128)
        {
            return _Index(bytes, 3);
        }
        else if (bytes < 1024)
        {
            return _Index(bytes - 128, 4) + group_array[0];
        }
        else if (bytes <= 8 * 1024)
        {
            return _Index(bytes - 1024, 7) + group_array[1] + group_array[0];
        }
        else if (bytes <= 64 * 1024)
        {
            return _Index(bytes - 8 * 1024, 10) + group_array[2] + group_array[1] + group_array[0];
        }
        else if (bytes <= 256 * 1024)
        {
            return _Index(bytes - 64 * 1024, 13) + group_array[3] + group_array[2] + group_array[1] + group_array[0];
        }
        else
        {
            assert(false);
        }

        return -1;
    }

    static size_t NumMoveSize(size_t size)
    {
        assert(size > 0);

        int num = MAX_BYTES / size;
        if (num < 2)
            num = 2;
        if (num > 512)
            num = 512;
        return num;
    }

    static size_t NumMovePage(size_t size)
    {
        size_t num = NumMoveSize(size);
        size_t npage = num * size;

        npage >>= PAGE_SHIFT;
        if (npage == 0)
            npage = 1;

        return npage;
    }
};

// 管理多个连续页的大块内存跨度结构
struct Span
{
    PAGE_ID _page_id = 0; // 大块内存的起始页号
    size_t _n = 0;        // 页的数量

    Span* _next = nullptr;      // 双项链表结构
    Span* _prev = nullptr;

    size_t objSzie = 0;   // 切好的小对象的大小

    size_t _useCount = 0; // 小内存块被分配给ThreadCache的计数
    void* _freeList = nullptr;  // 管理小块内存的自由链表

    bool _isuse = false;            // 是否在被使用
};


class SpanList
{
public:
    SpanList()
    {
        _head = new Span;
        _head->_next = _head;
        _head->_prev = _head;
    }

    void Insert(Span* pos, Span* newspan)
    {
        assert(pos);
        assert(newspan);

        // prev newspan pos
        Span* prev = pos->_prev;
        prev->_next = newspan;
        newspan->_prev = prev;
        newspan->_next = pos;
        pos->_prev = newspan;
    }

    Span* PopFront()
    {
        Span* span = _head->_next;
        Erase(span);
        return span;
    }

    void Erase(Span* pos)
    {
        assert(pos);
        assert(pos != _head);

        Span* prev = pos->_prev;
        Span* next = pos->_next;

        prev->_next = next;
        next->_prev = prev;
    }

    void PushFront(Span* span)
    {
        Insert(Begin(), span);
    }

    Span* Begin()
    {
        return _head->_next;
    }
    Span* End()
    {
        return _head;
    }

    bool Empty()
    {
        return _head == _head->_next;
    }

private:
    Span* _head;
public:
    std::mutex _mtx; // 桶锁
};